<?php
// @formatter:off
/**
 * @file WCParserBehaviorINCLUDE.php
 * @author Alejandro Dario Simi
 * @date $Date: 2013-07-24 01:55:33 +0000 (Wed, 24 Jul 2013) $
 *
 * $Id: WCParserBehaviorINCLUDE.php 99 2013-07-24 01:55:33Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/branches/wcomix-1.0/includes/parser/WCParserBehaviorINCLUDE.php $
 */
// @formatter:on

//
// Loading father class.
require_once dirname(__FILE__)."/WCParserBehavior.php";

//
// Adding the function to evaluate by this behavior.
$wcParserBehaviorMatrix["INCLUDE"] = "WCParserBehaviorINCLUDE";

/**
 * @class WCParserBehaviorINCLUDE This is a specific behavior that calls another
 * template file and perform a parsing operation on it. When it's used it looks
 * like:
 * @code
 * <:INCLUDE:/>/path/to/template<::/>
 * @endcode
 */
class WCParserBehaviorINCLUDE extends WCParserBehavior {
	/**
	 * @var string This is the type of warnings used when there's something
	 * wrong with a template to be included.
	 */
	const WarningNO_TEMPLATE = "INCLUDE_NOTEMPLATE";
	/**
	 * @var string This is the type of warnings used when there's something
	 * wrong an iterator.
	 */
	const WarningOVER = "INCLUDE_OVER";
	/**
	 * This method perform a check of the object, sets the current status
	 * (variable $this->_ok) and return it.
	 *
	 * @return boolean Returns the current status after a check.
	 */
	public function check() {
		//
		// A INCLUDE behavior must belong to a parser node.
		if($this->_node) {
			//
			// Loading node's children.
			$children = $this->_node->children();
			//
			// A INCLUDE behavior requires at least one child
			// belonging to its parser node.
			if(!isset($children[0])) {
				//
				// Its parser node has no children. Error message
				// is set and the internal status becomes false.
				$this->_errorMsg = "node has more than one children";
				$this->_ok = false;
			} elseif(!is_string($children[0])) {
				//
				// The first child of node is not a string and it
				// cannot be considered as a name. Error message
				// is set and the internal status becomes false.
				$this->_errorMsg = "node's first child is not a name";
				$this->_ok = false;
			} else {
				//
				// At this point, everything checks out.
				$this->_ok = true;
				$this->_errorMsg = "Ok";
			}
		} else {
			//
			// Behavior's node is not present. Error message is set
			// and the internal status becomes false.
			$this->_errorMsg = "INCLUDE node is not set";
			$this->_ok = false;
		}
		//
		// Returning current object status.
		return $this->isOk();
	}
	/**
	 * This method actually performs the inclusion of another template based
	 * on its node's data.
	 *
	 * @return string Returns the contents of a file parsed as if they where
	 * from a common template. Otherwise, returns false.
	 */
	public function get() {
		//
		// Setting the default value to be returned.
		$out = false;
		//
		// INCLUDE behavior will only be evaluated when this behavior has
		// no issues.
		if($this->isOk()) {
			//
			// Loading node's children.
			$children = $this->_node->children();
			//
			// Getting the first child as a template path.
			$template = "{$children[0]}";
			//
			// When the first character of the specified template is
			// not a slash, it is treated as a variable name where the
			// template path is stored.
			if($template[0] != "/") {
				$template = $this->_parser->$template;
			}
			//
			// Loading parameters.
			$params = $this->_node->params();
			//
			// Building a full system path for the template.
			// When the parameter 'full' is given, instead of using
			// templates root directory as prefix, the given path is
			// left intact.
			$path = WCSanitizer::SystemPath((isset($params["full"]) ? "" : $this->_parser->templatesRoot()).$template);
			//
			// Checking template.
			if($template && is_file($path) && is_readable($path)) {
				//
				// At this point, the template was determined and
				// it is a readable file.
				//
				// Internally, this behavior always works as if
				// has to load the template many times. Therefore,
				// a first step is always set.
				$over = array("INCLUDESINGLESTEP" => array());
				//
				// Checking if there's an array that will specify
				// how many time the template must be included.
				// This is done through the parameter 'over'.
				if(isset($params["over"])) {
					//
					// Creating a shortcut to the array's name.
					$overArray = $params["over"];
					//
					// Getting the array.
					$over = $this->_parser->$overArray;
				}
				//
				// Checking that there's an array to work with.
				if(is_array($over) && count($over) > 0) {
					//
					// Setting the default text to be returned.
					$out = "";
					//
					// Analyzing each step of the array.
					foreach($over as $extraValues) {
						//
						// Creating a parser to manage the
						// sub-template.
						$subRoot = new WCParser();
						//
						// Coping all current variables to
						// the new parser.
						$subRoot->massiveAssign($this->_parser->variables());
						//
						// Coping the template's root
						// directory. Sub-templates may
						// also include other templates.
						$subRoot->templatesRoot($this->_parser->templatesRoot());
						//
						// Checking if there's a parameter
						// called 'no-warnings' set, in
						// such case, sub-parser warnings
						// are disabled, otherwise, it
						// depends on current parser
						// settings.
						if(isset($params["no-warnings"])) {
							$subRoot->noWarnings();
						} else {
							$subRoot->noWarnings(!$this->_parser->showWarnings());
						}
						//
						// Checking if there's a parameter
						// called 'no-summary' set, in
						// such case, sub-parser summaries
						// are disabled, otherwise, it
						// depends on current parser
						// settings.
						if(isset($params["no-summary"])) {
							$subRoot->noSummary();
						} else {
							$subRoot->noSummary(!$this->_parser->showSummary());
						}
						//
						// Setting the maximum depth with
						// one less level on the sub-
						// parser.
						$subRoot->setMaxDepth($this->_parser->maxDepth() - 1);
						//
						// Loading the specified template
						// in the sub-parser.
						$subRoot->load($template, isset($params["full"]));
						//
						// At this point, each element of
						// the the array that is being
						// walked over is treated as an
						// associative array representing
						// variable definitions.
						// This allows each step to
						// generate a different result for
						// the same template.
						$subRoot->massiveAssign($extraValues);
						//
						// Parsing and appending the
						// results of the sub-parser.
						$out .= $subRoot->parse();
						//
						// Sub-parser is no longer needed.
						unset($subRoot);
					}
					//
					// When there's a parameter 'padding' set,
					// every line must be indented with as
					// many TAB characters as the number given
					// by the parameter 'padding'.
					if(isset($params['padding'])) {
						//
						// General spacer.
						$padding = str_repeat("\t", $params['padding']);
						//
						// When the parameter 'nfl' is
						// given, the first line is not
						// indented.
						$out = (isset($params["nfl"]) ? "" : $padding).str_replace("\n", "\n".$padding, $out);
					}
				} else {
					//
					// At this point, something went wrong
					// with the list of iterations.
					//
					// If the parameter '!' is given, this
					// kind error of errors are ignored and
					// an empty string is returned as result
					// of the evaluation.
					if(isset($params["!"])) {
						$out = "";
					} else {
						$itMsg=isset($params["over"])? "Iterator '{$params["over"]}'":"Default iterator";


						if(is_array($over)) {
							$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningOVER, "{$itMsg} is not an array, in node '{$this->_node->id()}'", false, false, __CLASS__);
						} else {
							$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningOVER, "{$itMsg} is an array of no elements, in node '{$this->_node->id()}'", false, false, __CLASS__);
						}
					}
				}
			} else {
				//
				// At this point, something went wrong with the
				// template.
				//
				// If the parameter '!' is given, this kind error
				// of errors are ignored and an empty string is
				// returned as result of the evaluation.
				if(isset($params["!"])) {
					$out = "";
				} else {
					if(!$template) {
						$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningNO_TEMPLATE, "No template given at node '{$this->_node->id()}'", false, false, __CLASS__);
					} elseif(!is_file($path)) {
						$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningNO_TEMPLATE, "Template '{$template}' given".($template != "{$children[0]}" ? " as '{$children[0]}'" : "")." at node '{$this->_node->id()}' is not a file", false, false, __CLASS__);
					} elseif(!is_readable($path)) {
						$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningNO_TEMPLATE, "Template '{$template}' given".($template != "{$children[0]}" ? " as '{$children[0]}'" : "")." at node '{$this->_node->id()}' is not a readable", false, false, __CLASS__);
					}
				}
			}
		}
		//
		// Returning evaluation results.
		return $out;
	}
	/**
	 * This method redefines the inherited class initializer.
	 */
	protected function init() {
		//
		// Setting a type of warnings used when there's something wrong
		// with a template to be included.
		$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningNO_TEMPLATE, false, false, "INCLUDE: specified template issues");
		//
		// Setting a type of warnings used when there's something wrong an
		// iterator.
		$this->_parser->setWarning(WCParserBehaviorINCLUDE::WarningOVER, false, false, "INCLUDE: iterator issues");
	}
}
?>